package org.giovanolli.mumi.controller.payment;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.servlet.http.HttpServletResponse;

import org.giovanolli.mumi.controller.AbstractController;
import org.giovanolli.mumi.controller.AbstractModel;
import org.giovanolli.mumi.entities.Bill;
import org.giovanolli.mumi.entities.BillDetail;
import org.giovanolli.mumi.entities.filter.BillFilter;
import org.giovanolli.mumi.entities.filter.PatientFilter;
import org.giovanolli.mumi.entities.filter.SpecialityFilter;
import org.giovanolli.mumi.export.BillTemplate;
import org.giovanolli.mumi.service.AttentionTimeService;
import org.giovanolli.mumi.service.BillService;
import org.giovanolli.mumi.service.PatientService;
import org.giovanolli.mumi.service.Service;
import org.giovanolli.mumi.service.SpecialityService;
import org.giovanolli.mumi.view.datamodel.DefaultSelectionDataModelListener;
import org.giovanolli.mumi.view.datamodel.SelectableDataModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfWriter;

/**
 * The Class BillController.
 */
@Controller("billController")
@ViewScoped
public class BillController extends AbstractController<Bill> {

	/** The service. */
	@Autowired
	private BillService service;

	/** The patient service. */
	@Autowired
	private PatientService patientService;

	/** The attention time service. */
	@Autowired
	private AttentionTimeService attentionTimeService;

	/** The speciality service. */
	@Autowired
	private SpecialityService specialityService;

	/** The model. */
	@Autowired
	private BillModel model;

	/**
	 * Adds the bill detail event.
	 */
	public void addBillDetailEvent() {
		model.setEditedBillDetail(new BillDetail());
	}

	/**
	 * Amount recalc event.
	 * 
	 * @param actionEvent
	 *            the action event
	 */
	@Transactional(readOnly = true)
	public void amountRecalcEvent(AjaxBehaviorEvent actionEvent) {
		BillDetail editedBillDetail = model.getEditedBillDetail();
		editedBillDetail.setAmount(editedBillDetail.getQuantity() * editedBillDetail.getSpecialistFee().getAmount());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#bindEntityToModel()
	 */
	@Override
	protected void bindEntityToModel() {
		Bill editedBill = model.getEditedEntity();
		Date billDate = editedBill.getDate();
		if (editedBill.getDate() == null) {
			billDate = new Date();
		}
		model.setDate(billDate);
		model.setPatient(editedBill.getPatient());
		model.setAmount(editedBill.getAmount());
		model.setPaymentType(editedBill.getPaymentType());
		model.setPatientPrepaid(editedBill.getPatientPrepaid());
		// model.setSelectableBillDetails(new
		// SelectionDataModel<BillDetail>(service.getNonBilledDetails(model.getPatient())));
		DefaultSelectionDataModelListener<BillDetail> selectionListener = new DefaultSelectionDataModelListener<BillDetail>(new HashSet<BillDetail>(editedBill.getBillDetails()));
		List<BillDetail> billDetailList = new ArrayList<BillDetail>();
		if (editedBill.getPatient() != null) {
			billDetailList = service.getNonBilledDetails(editedBill.getPatient());
		}
		SelectableDataModel<BillDetail> permissionDataModel = new SelectableDataModel<BillDetail>(billDetailList, selectionListener);
		model.setBillDetailsDataModel(permissionDataModel);
		model.setBillDetailsSelectionListener(selectionListener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#bindModelToEntity()
	 */
	@Override
	protected void bindModelToEntity() {
		Bill editedBill = model.getEditedEntity();
		editedBill.setDate(model.getDate());
		editedBill.setPatient(model.getPatient());
		editedBill.setAmount(model.getAmount());
		editedBill.setPaymentType(model.getPaymentType());
		editedBill.setPatientPrepaid(model.getPatientPrepaid());
		// editedBill.getBillDetails().clear();
		// editedBill.getBillDetails().addAll(Arrays.asList(model.getBillDetails()));

		// editedBill.getBillDetails().clear();
		// editedBill.getBillDetails().addAll(model.getBillDetailsSelectionListener().getSelectedElements());
	}

	/**
	 * Calculate total amount.
	 */
	public void calculateTotalAmount() {
		Double total = 0d;
		for (BillDetail billDetail : model.getEditedEntity().getBillDetails()) {
			total += billDetail.getAmount();
		}
		model.setAmount(total);
	}

	/**
	 * Confirm delete bill detail event.
	 */
	public void confirmDeleteBillDetailEvent() {
		model.getEditedEntity().getBillDetails().remove(model.getEditedBillDetail());
		calculateTotalAmount();
	}

	/**
	 * Confirm save bill detail event.
	 */
	public void confirmSaveBillDetailEvent() {
		BillDetail editedBillDetail = model.getEditedBillDetail();

		for (BillDetail billDetail : model.getEditedEntity().getBillDetails()) {
			if (billDetail.getUid().equals(model.getEditedBillDetail().getUid())) {

				/*
				 * billDetail.setAreaCode(editedBillDetail.getAreaCode()); billDetail.setComment(editedBillDetail.getComment());
				 * billDetail.setCountryCode(editedBillDetail.getCountryCode()); billDetail.setBillDetailNumber(editedBillDetail.getBillDetailNumber());
				 */
				return;
			}
		}
		editedBillDetail.setAmount(editedBillDetail.getQuantity() * editedBillDetail.getSpecialistFee().getAmount());
		model.getEditedEntity().getBillDetails().add(model.getEditedBillDetail());
		calculateTotalAmount();
	}

	/**
	 * Creates the pdf.
	 */
	@Transactional(readOnly = true)
	public void createPDF() {
		System.out.println("entered createPDF");
		FacesContext context = FacesContext.getCurrentInstance();
		HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
		response.setContentType("application/pdf");
		response.setHeader("Content-disposition", "attachment; filename=comp_" + model.getEditedEntity().getBillId() + ".pdf");
		try {

			// Get the text that will be added to the PDF
			String text = "test";
			// step 1
			Document document = new Document();
			// step 2

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			PdfWriter.getInstance(document, baos);
			// step 3
			// document.open();
			// new ReportController().preProcessPDF(document);
			// step 4
			// document.add(new Paragraph(text));
			// step 5
			// document.close();
			new BillTemplate().applyTemplate(document, model.getEditedEntity());

			// setting some response headers
			response.setHeader("Expires", "0");
			response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
			response.setHeader("Pragma", "public");
			// setting the content type
			response.setContentType("application/pdf");
			// the contentlength
			response.setContentLength(baos.size());
			// write ByteArrayOutputStream to the ServletOutputStream
			OutputStream os = response.getOutputStream();
			baos.writeTo(os);
			os.flush();
			os.close();
			System.out.println("flushed and closed the outputstream");

		} catch (DocumentException e) {
			System.out.println("error: " + e);
		} catch (IOException e) {
			System.out.println("error: " + e);
		} catch (Exception ex) {
			System.out.println("error: " + ex.getMessage());
		}
		context.responseComplete();
		System.out.println("context.responseComplete()");
	}

	// BILL DETAIL EVENTS

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#getEntityClass()
	 */
	protected Class<Bill> getEntityClass() {
		return Bill.class;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#getModel()
	 */
	@Override
	protected AbstractModel<Bill> getModel() {
		return model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#getService()
	 */
	@Override
	protected Service<Bill> getService() {
		return service;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#init()
	 */
	public void init() {
		super.init();
		model.setFilter(new BillFilter());
		populateNonEntityPropertiesToModel();
	}

	// ///////////////////
	// METODOS DE CAMBIO DE COMBOS DE BUSQUEDA
	// //////////////////

	/**
	 * On patient change.
	 * 
	 * @param actionEvent
	 *            the action event
	 */
	public void onPatientChange(AjaxBehaviorEvent actionEvent) {
		model.setSelectableBillDetails(new BillDetailSelectionDataModel(service.getNonBilledDetails(model.getPatient())));
		DefaultSelectionDataModelListener<BillDetail> selectionListener = new DefaultSelectionDataModelListener<BillDetail>(new HashSet<BillDetail>(model.getEditedEntity()
		        .getBillDetails()));
		List<BillDetail> billDetailList = new ArrayList<BillDetail>();
		if (model.getPatient() != null) {
			billDetailList = service.getNonBilledDetails(model.getPatient());
		}
		SelectableDataModel<BillDetail> permissionDataModel = new SelectableDataModel<BillDetail>(billDetailList, selectionListener);
		model.setBillDetailsDataModel(permissionDataModel);
		model.setBillDetailsSelectionListener(selectionListener);
		model.setBillDetails(null);
	}

	/**
	 * On speciality change.
	 * 
	 * @param actionEvent
	 *            the action event
	 */
	@Transactional(readOnly = true)
	public void onSpecialityChange(AjaxBehaviorEvent actionEvent) {
		model.setSelectableSpecialists(model.getSpeciality().getSpecialists());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.giovanolli.mumi.controller.AbstractController#populateNonEntityPropertiesToModel()
	 */
	@Override
	public void populateNonEntityPropertiesToModel() {
		model.setSelectablePatients(patientService.getList(new PatientFilter()));
		model.setSelectableSpecialities(specialityService.getList(new SpecialityFilter()));
	}

}
